package es.udima.geo.geoserver.rest;

import java.util.Collection;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import es.udima.geo.geoserver.business.UserController;
import es.udima.geo.geoserver.entities.User;
import es.udima.geo.geoserver.entities.UserAction;
import es.udima.geo.geoserver.entities.UserActivityLog;
import es.udima.geo.geoserver.entities.UserSession;
import es.udima.geo.geoserver.entities.UserSessionError;
import es.udima.geo.geoserver.entities.UserUpdateResult;
import es.udima.geo.geoserver.entities.UserUpdateResultError;
import es.udima.geo.geoserver.rest.entities.IResponseError;
import es.udima.geo.geoserver.rest.entities.UserCreateRequest;
import es.udima.geo.geoserver.rest.entities.UserLoginError;
import es.udima.geo.geoserver.rest.entities.UserLoginRequest;
import es.udima.geo.geoserver.rest.entities.UserLoginResponse;
import es.udima.geo.geoserver.rest.entities.UserLogoutRequest;
import es.udima.geo.geoserver.rest.entities.UserLogoutResponse;
import es.udima.geo.geoserver.rest.entities.UserRegisterResponse;
import es.udima.geo.geoserver.rest.entities.UserRetrieveError;
import es.udima.geo.geoserver.rest.entities.UserRetrieveRequest;
import es.udima.geo.geoserver.rest.entities.UserRetrieveResponse;
import es.udima.geo.geoserver.rest.entities.UserSessionResponse;
import es.udima.geo.geoserver.rest.entities.UserSessionValidationRequest;
import es.udima.geo.geoserver.rest.entities.UserUpdateRequest;
import es.udima.geo.geoserver.rest.entities.UserUpdateResponse;

@Path("/users")
public class UserService {

    public UserService() {
    }

    /**
     * 
     * @param params
     * @return
     */
    @POST
    @Path("/login")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public UserLoginResponse loginUser(UserLoginRequest req) {
	String userName = req.getUserName();
	String password = req.getPassword();

	UserLoginResponse res = new UserLoginResponse();

	if (userName.isEmpty()) {
	    res.addResponseError(UserLoginError.EMPTY_USERNAME);
	}

	if (password.isEmpty()) {
	    res.addResponseError(UserLoginError.EMPTY_PASSWORD);
	}

	if (res.isResponseSuccessful()) {
	    UserController uc = new UserController();
	    User userRead = uc.retrieveUserByUserName(userName);
	    if (userRead == null) {
		res.addResponseError(UserLoginError.INCORRECT_USERNAME);
	    } else if (!password.equals(userRead.getPassword())) {
		res.addResponseError(UserLoginError.INCORRECT_PASSWORD);
	    } else {
		UserSession us = uc.connectUser(userRead);
		res.setUserSession(us);
	    }
	}

	return res;
    }

    /**
     * 
     * @param params
     * @return
     */
    @POST
    @Path("/logout")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public UserLogoutResponse logoutUser(UserLogoutRequest req) {
	UserController uc = new UserController();

	String activityId = null;
	if (req.getUserSession() != null) {
	    UserActivityLog activity = new UserActivityLog();
	    activity.setUserId(req.getUserSession().getUserId());
	    activity.setSessionToken(req.getUserSession().getSessionToken());
	    activity.setAction(UserAction.LOGOUT);
	    activityId = uc.startUserActivityLog(activity);
	}

	uc.disconnectUser(req.getUserSession());

	if (activityId != null) {
	    uc.terminateUserActivityLog(activityId);
	}

	return new UserLogoutResponse();
    }

    /**
     * 
     * @param userId
     * @return
     */
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public UserRetrieveResponse retrieveUser(UserRetrieveRequest req) {

	UserController uc = new UserController();
	UserRetrieveResponse res = new UserRetrieveResponse();

	String activityId = null;
	if (req.getUserSession() != null) {
	    UserActivityLog activity = new UserActivityLog();
	    activity.setUserId(req.getUserSession().getUserId());
	    activity.setSessionToken(req.getUserSession().getSessionToken());
	    activity.setAction(UserAction.RETRIEVE_USER_DATA);
	    activityId = uc.startUserActivityLog(activity);
	}

	Collection<UserSessionError> sessionErrors = uc.consumeUserSession(req.getUserSession());
	if (!sessionErrors.isEmpty()) {
	    res.addResponseErrors(translateUserSessionErrors(sessionErrors));
	} else {
	    User u = uc.retrieveUserByUserId(req.getUserId());
	    if (u == null) {
		res.addResponseError(UserRetrieveError.USER_NOT_EXISTS);
	    } else {
		res.setUser(u);
		if (activityId != null) {
		    uc.terminateUserActivityLog(activityId);
		}
	    }
	}
	return res;
    }

    /**
     * 
     * @param params
     * @return
     */
    @POST
    @Path("/register")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public UserRegisterResponse registerUser(UserCreateRequest req) {
	UserRegisterResponse res = new UserRegisterResponse();
	UserController uc = new UserController();
	req.getUser().setActive(true);
	UserUpdateResult ur = uc.createUser(req.getUser());
	if (ur.isUpdateSuccessful()) {
	    res.setUser(ur.getUser());
	} else {
	    res.addResponseErrors(translateUserUpdateErrors(ur.getErrors()));
	}

	return res;
    }

    /**
     * 
     * @param params
     * @return
     */
    @POST
    @Path("/update")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public UserUpdateResponse updateUser(UserUpdateRequest req) {
	UserController uc = new UserController();
	UserUpdateResponse res = new UserUpdateResponse();

	String activityId = null;
	if (req.getUserSession() != null) {
	    UserActivityLog activity = new UserActivityLog();
	    activity.setUserId(req.getUserSession().getUserId());
	    activity.setSessionToken(req.getUserSession().getSessionToken());
	    activity.setAction(UserAction.UPDATE_USER_DATA);
	    activityId = uc.startUserActivityLog(activity);
	}

	Collection<UserSessionError> sessionErrors = uc.consumeUserSession(req.getUserSession());
	if (!sessionErrors.isEmpty()) {
	    res.addResponseErrors(translateUserSessionErrors(sessionErrors));
	} else {
	    req.getUser().setId(req.getUserSession().getUserId());
	    UserUpdateResult ur = uc.updateUser(req.getUser());
	    if (ur.isUpdateSuccessful()) {
		res.setUser(ur.getUser());
		if (activityId != null) {
		    uc.terminateUserActivityLog(activityId);
		}
	    } else {
		res.addResponseErrors(translateUserUpdateErrors(ur.getErrors()));
	    }
	}
	return res;
    }

    /**
     * 
     * @param req
     * @return
     */
    @POST
    @Path("/changepwd")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public UserUpdateResponse updateUserPassword(UserUpdateRequest req) {

	UserController uc = new UserController();
	UserUpdateResponse res = new UserUpdateResponse();

	String activityId = null;
	if (req.getUserSession() != null) {
	    UserActivityLog activity = new UserActivityLog();
	    activity.setUserId(req.getUserSession().getUserId());
	    activity.setSessionToken(req.getUserSession().getSessionToken());
	    activity.setAction(UserAction.UPDATE_USER_PASSWORD);
	    activityId = uc.startUserActivityLog(activity);
	}

	Collection<UserSessionError> sessionErrors = uc.consumeUserSession(req.getUserSession());
	if (!sessionErrors.isEmpty()) {
	    res.addResponseErrors(translateUserSessionErrors(sessionErrors));
	} else {
	    User u = req.getUser();
	    u.setId(req.getUserSession().getUserId());
	    UserUpdateResult ur = uc.updateUserPassword(u);
	    if (!ur.isUpdateSuccessful()) {
		res.addResponseErrors(translateUserUpdateErrors(ur.getErrors()));
	    } else {
		if (activityId != null) {
		    uc.terminateUserActivityLog(activityId);
		}
	    }
	}
	return res;
    }

    /**
     * 
     * @param req
     * @return
     */
    @POST
    @Path("/validateSession")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public UserSessionResponse validateUserSession(UserSessionValidationRequest req) {
	UserController uc = new UserController();
	UserSessionResponse res = new UserSessionResponse();
	Collection<UserSessionError> sessionErrors = uc.consumeUserSession(req.getUserSession());
	if (!sessionErrors.isEmpty()) {
	    res.addResponseErrors(translateUserSessionErrors(sessionErrors));
	}
	return res;
    }

    /*-----------------------------------------------------------------------------------------------*/

    /**
     * 
     * @param errors
     * @return
     */
    private Collection<IResponseError> translateUserUpdateErrors(Collection<UserUpdateResultError> errors) {
	return new RestServiceErrorHelper().translateUserUpdateErrors(errors);
    }

    /**
     * 
     * @param errors
     * @return
     */
    private Collection<IResponseError> translateUserSessionErrors(Collection<UserSessionError> errors) {
	return new RestServiceErrorHelper().translateUserSessionErrors(errors);
    }

}
